package com.wofish.core.redis;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.wofish.core.exception.RedisDataAccessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Tuple;
import redis.clients.jedis.exceptions.JedisException;

import java.util.*;

/**
 */
@Service
@Slf4j
public class JedisService {


    @Autowired
    private JedisPoolManager readJedisPoolManager;

    @Autowired
    private JedisPoolManager writeJedisPoolManager;

    private static final int DEFAULT_ACQUIRY_RESOLUTION_MILLIS = 100;


    private JedisLock jedisLock;

    private String lockKey;

    private int expireMsecs = 5 * 1000;

    private int timeoutMsecs = 5 * 1000;

    private volatile boolean locked = false;

    public String getLockKey() {
        return lockKey;
    }

    public void setex(String key, int seconds, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.setex(key, seconds, value);
        } catch (Exception e) {
            log.error("setex from jedis error. key:{} value:{}", key, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public Boolean setnx(String key, String value, Integer expireSeconds) {
        Jedis wjedis = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            long result = wjedis.setnx(key, value);
            if (result == 1) {
                return Boolean.TRUE;
            }
        } catch (Exception e) {
            log.error("setnx from jedis error. key:{}", key);
        } finally {
            try {
                wjedis.expire(key, expireSeconds);
            } catch (Exception e) {
                log.error("设置超时时间失败[key={}, value={},expireSeconds={}]", key, value, expireSeconds, e);
            }

            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return Boolean.FALSE;
    }

    public synchronized boolean lock(String lockKeys, int timeoutMsecss, int expireMsecss) throws InterruptedException {
        this.lockKey = lockKeys + "_lock";
        this.timeoutMsecs = timeoutMsecss;
        this.expireMsecs = expireMsecss;
        int timeout = timeoutMsecs;
        Jedis rjedis = readJedisPoolManager.getJedis();
        while (timeout >= 0) {
            long expires = System.currentTimeMillis() + expireMsecs + 1;
            String expiresStr = String.valueOf(expires); //锁到期时间
            if (rjedis.setnx(lockKey, expiresStr) == 1) {
                // lock acquired
                locked = true;
                return true;
            }
            String currentValueStr = rjedis.get(lockKey); //redis里的时间
            if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
                //判断是否为空，不为空的情况下，如果被其他线程设置了值，则第二个条件判断是过不去的
                // lock is expired
                String oldValueStr = rjedis.getSet(lockKey, expiresStr);
                //获取上一个锁到期时间，并设置现在的锁到期时间，
                //只有一个线程才能获取上一个线上的设置时间，因为jedis.getSet是同步的
                if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
                    //防止误删（覆盖，因为key是相同的）了他人的锁——这里达不到效果，这里值会被覆盖，但是因为什么相差了很少的时间，所以可以接受

                    //[分布式的情况下]:如过这个时候，多个线程恰好都到了这里，但是只有一个线程的设置值和当前值相同，他才有权利获取锁
                    // lock acquired
                    locked = true;
                    return true;
                }
            }
            timeout = DEFAULT_ACQUIRY_RESOLUTION_MILLIS;

            /*
                延迟100 毫秒,  这里使用随机时间可能会好一点,可以防止饥饿进程的出现,即,当同时到达多个进程,
                只会有一个进程获得锁,其他的都用同样的频率进行尝试,后面有来了一些进行,也以同样的频率申请锁,这将可能导致前面来的锁得不到满足.
                使用随机的等待时间可以一定程度上保证公平性
             */
            Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);

        }
        return false;
    }

    public synchronized void unlock(String lockKeys) {
        this.lockKey = lockKeys + "_lock";
        Jedis rjedis = readJedisPoolManager.getJedis();
        if (locked) {
            rjedis.del(lockKey);
            locked = false;
        }
    }


    public byte[] readByte(String key) throws RedisDataAccessException {
        byte[] ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            byte[] jedisKey = key.getBytes();
            byte[] content = rjedis.get(jedisKey);
            if (content != null && content.length > 0) {
                ret = content;
            }
        } catch (Exception e) {
            log.error("read from jedis error. key:{} msg:{}", key, e);
            throw new RedisDataAccessException("redis read error.", e);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    /**
     * 写入redis，并指定失效时间点
     *
     * @param key
     * @param content  数据
     * @param deadLine 失效时间点
     */
    public void write(String key, String content, Date deadLine) {
        Jedis wjedis = null;
        long now = System.currentTimeMillis();
        long dead = deadLine.getTime();
        int expireTime = (int) (dead - now) / (1000 * 60);//转换为分钟
        if (expireTime <= 0) {
            log.warn("request ignored .Date:{} msg:{}", new Object[]{deadLine, " invalid deadLine:The deadLine must be one minute later than currentTime "});
            return;
        } else {
            try {
                wjedis = writeJedisPoolManager.getJedis();
                byte[] data = null;
                if (content != null) {
                    data = content.getBytes();
                }
                byte[] jedisKey = key.getBytes();
                wjedis.setex(jedisKey, expireTime, data);
            } catch (Exception e) {
//                log.error("write to jedis error. key:{} data:{} msg:{}", key, content, e);
                throw new RedisDataAccessException("redis read error.", e);
            } finally {
                if (wjedis != null) {
                    writeJedisPoolManager.returnJedis(wjedis);
                }
            }
        }
    }

    public void write(String key, byte[] content, int expireTime) throws RedisDataAccessException {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            byte[] data = content;
            byte[] jedisKey = key.getBytes();
            wjedis.setex(jedisKey, expireTime, data);
        } catch (Exception e) {
            throw new RedisDataAccessException("Failed to write key " + key, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    /**
     * 写入redis，并指定失效时间点
     *
     * @param key
     * @param content    数据
     * @param expireTime 失效时长(秒)
     */
    public void write(String key, String content, int expireTime) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            byte[] data = null;
            if (content != null) {
                data = content.getBytes();
            }
            byte[] jedisKey = key.getBytes();

            wjedis.setex(jedisKey, expireTime, data);
        } catch (Exception e) {
//            log.error("write to jedis error. key:{} data:{} msg:{}", key, content, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void set(String key, String content) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.set(key, content);
        } catch (Exception e) {
            log.error("set to jedis error. key:{} data:{} msg:{}", key, content, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void set(String key, String content, int expire) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.set(key, content);
            if (expire >= 0) {
                wjedis.expire(key, expire);
            }
        } catch (Exception e) {
            log.error("set to jedis error. key:{} data:{} msg:{}", key, content, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void del(String key) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.del(key);
        } catch (Exception e) {
            log.error("delete from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public String get(String key) {
        String ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.get(key);
        } catch (Exception e) {
            log.error("get from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public String read(String key) {
        String ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.get(key);
        } catch (Exception e) {
            log.error("read from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public Long incr(String key) {
        Long wet = null;
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wet = wjedis.incr(key);
        } catch (Exception e) {
            log.error("incr from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                readJedisPoolManager.returnJedis(wjedis);
            }
        }
        return wet;
    }

    public Long incrBy(String key, long inet) {
        Long ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.incrBy(key, inet);
        } catch (Exception e) {
            log.error("incrBy from jedis error. key:{} inet:{}", key, inet);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public Long decr(String key) {
        Long wet = null;
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wet = wjedis.decr(key);
        } catch (Exception e) {
            log.error("decr from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                readJedisPoolManager.returnJedis(wjedis);
            }
        }
        return wet;
    }

    public Long decrBy(String key, long inet) {
        Long ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.decrBy(key, inet);
        } catch (Exception e) {
            log.error("decrBy from jedis error. key:{} inet:{}", key, inet);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public String lindex(String key, long index) {
        String ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.lindex(key, index);
        } catch (Exception e) {
            log.error("lindex from jedis error. key:{} index:{}", key, index);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public void lpush(String key, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.lpush(key, value);
        } catch (Exception e) {
            log.error("lpush from jedis error. key:{}  value:{}", key, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public String lpop(String key) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            return wjedis.lpop(key);
        } catch (Exception e) {
            log.error("rpop from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return null;
    }

    public void rpush(String key, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.rpush(key, value);
        } catch (Exception e) {
            log.error("rpush from jedis error. key:{}  value:{}", key, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public Long llen(String key) {
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            return rjedis.llen(key);
        } catch (Exception e) {
            log.error("llen from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return 0L;
    }

    public Long hlen(String key) {
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            return rjedis.hlen(key);
        } catch (Exception e) {
            log.error("hlen from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return 0L;
    }

    public List<String> lrange(String key, long begin, long end) {
        Jedis rjedis = null;
        List<String> result = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            result = rjedis.lrange(key, begin, end);
            return result;
        } catch (Exception e) {
            log.error("llen from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return null;
    }

    public Long lrem(String key, long count, String value) {
        Jedis rjedis = null;
        Long result = 0L;
        try {
            rjedis = writeJedisPoolManager.getJedis();
            result = rjedis.lrem(key, count, value);
            return result;
        } catch (Exception e) {
            log.error("lrem from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                writeJedisPoolManager.returnJedis(rjedis);
            }
        }
        return result;
    }

    public String rpop(String key) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            return wjedis.rpop(key);
        } catch (Exception e) {
            log.error("rpop from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return null;
    }

    public String hget(String key, String field) {
        String ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.hget(key, field);
        } catch (Exception e) {
            log.error("hget from jedis error. key=" + key + "field=" + field, e);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public void hset(String key, String field, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hset(key, field, value);
        } catch (Exception e) {
            log.error("hset from jedis error. key:{} field:{} value:{}", key, field, value, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public List<String> hmread(String key, String... field) {
        List<String> ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            if (field.length > 0) {
                ret = rjedis.hmget(key, field);
            }
        } catch (Exception e) {
            log.error("hmread from jedis error. key=" + key + "field=" + field, e);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public Map<String, String> hgetAll(String key) {
        Map<String, String> ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.hgetAll(key);
        } catch (Exception e) {
            log.error("hget from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public Set<String> hgetAllKeysByKey(String key) {
        Set<String> ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.hkeys(key);
        } catch (Exception e) {
            log.error("hreadAllByKey from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public Map<String, String> hgetAllBykey(String key) {
        Map<String, String> ret = null;
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            ret = rjedis.hgetAll(key);
        } catch (Exception e) {
            log.error("hreadAllByKey from jedis error. key:{}", key);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return ret;
    }

    public void hwrite(String key, String field, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hset(key, field, value);
        } catch (Exception e) {
            log.error("hwrite from jedis error. key:{} field:{} value:{}", key, field, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void hdelete(String key, String field, String value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hdel(key, field);
        } catch (Exception e) {
            log.error("hdelete from jedis error. key:{} field:{} value:{}", key, field, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void hdel(String key, String field) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hdel(key, field);
        } catch (Exception e) {
            log.error("hdel from jedis error. key:{} field:{}", key, field);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public Long hincr(String key, String field) {
        return hincrBy(key, field, 1L);
    }

    public Long hincrBy(String key, String field, Long value) {
        Jedis wjedis = null;
        Long result = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            result = wjedis.hincrBy(key, field, value);
        } catch (Exception e) {
            log.error("hincrBy from jedis error. key:{} field:{} value:{}", key, field, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return result;
    }

    public void hdeleteKey(String key) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.del(key);
        } catch (Exception e) {
            log.error("delete from jedis error. key:{}", key);
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void hwrite(String key, Map<String, String> value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hmset(key, value);
        } catch (Exception e) {
            log.error("hwrite from jedis error. key:{} value:{}", key, value);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void disableCache(String key) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.expire(key, 0);
        } catch (Exception e) {
            log.error("disableCache error. key:{} msg:{}", key, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void remove(String key) throws RedisDataAccessException {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.del(key);
        } catch (Exception e) {
            log.error("remove error. key:{} msg:{}", key, e);
            throw new RedisDataAccessException("Failed to remove key " + key, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void hincrbyfloat(String key, String property, double value) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            wjedis.hincrByFloat(key, property, value);
        } catch (Exception e) {
            log.error("hincrbyfloat from jedis error. key:=" + key + "&value=" + value, e);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }


    public String lockWithTimeout(String locaName,
                                  long acquireTimeout, long timeout) {
        Jedis conn = null;
        String retIdentifier = null;
        String lockKey = null;
        try {
            // 获取连接
            conn = writeJedisPoolManager.getJedis();
            // 随机生成一个value
            String identifier = UUID.randomUUID().toString();
            // 锁名，即key值
            lockKey = "lock:" + locaName;
            // 超时时间，上锁后超过此时间则自动释放锁
            int lockExpire = (int) (timeout / 1000);

            // 获取锁的超时时间，超过这个时间则放弃获取锁
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {
                if (conn.setnx(lockKey, identifier) == 1) {
                    conn.expire(lockKey, lockExpire);
                    // 返回value值，用于释放锁时间确认
                    retIdentifier = identifier;
                    return retIdentifier;
                }
                // 返回-1代表key没有设置超时时间，为key设置一个超时时间
                if (conn.ttl(lockKey) == -1) {
                    conn.expire(lockKey, lockExpire);
                }
            }
        } catch (JedisException e) {
            e.printStackTrace();
        } finally {
            log.info("lock name: {}", lockKey);
            if (conn != null) {
                conn.close();
            }
        }
        return retIdentifier;
    }

    /**
     * 释放锁
     *
     * @param lockName   锁的key
     * @param identifier 释放锁的标识
     * @return
     */
    public boolean releaseLock(String lockName, String identifier) {
        Jedis conn = null;
        String lockKey = "lock:" + lockName;
        boolean retFlag = false;
        try {
            conn = writeJedisPoolManager.getJedis();
            while (true) {
                // 监视lock，准备开始事务
                conn.watch(lockKey);
                // 通过前面返回的value值判断是不是该锁，若是该锁，则删除，释放锁
                if (identifier.equals(conn.get(lockKey))) {
                    Transaction transaction = conn.multi();
                    transaction.del(lockKey);
                    List<Object> results = transaction.exec();
                    if (results == null) {
                        continue;
                    }
                    retFlag = true;
                }
                conn.unwatch();
                break;
            }
        } catch (JedisException e) {
            e.printStackTrace();
        } finally {
//            log.info("锁名称：" + lockKey);
            if (conn != null) {
                conn.close();
            }
        }
        return retFlag;
    }

    public Double zincrby(String key, double score, String member) {
        Jedis wjedis = null;
        Double totalScore = new Double(0);
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            totalScore = wjedis.zincrby(key, score, member);
        } catch (Exception e) {
            log.error("zincrby from jedis error. key:{} score:{} member:{}", key, score, member);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return totalScore;
    }

    public void batchIncrCycleRank(String id, double score, List<String> rankKeys, Integer seconds) {

        Jedis wjedis = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            Pipeline pipe = wjedis.pipelined();
            for (String rankKey : rankKeys) {
                pipe.zincrby(rankKey, score, id);
                if (seconds != null) {
                    pipe.expire(rankKey, seconds);
                }
            }
            pipe.sync();
        } catch (Exception e) {
            log.error("batchIncrCycleRank from jedis error. id:{} score:{},rankKeys:{}, seconds:{}",
                    id, score, rankKeys,seconds);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public void zadd(String key, double score, String member) {
        Jedis wjedis = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            wjedis.zadd(key, score, member);
        } catch (Exception e) {
            log.error("zincrby from jedis error. key:{} score:{} member:{}", key, score, member);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }

    public Long zrem(String key, String member) {
        Jedis wjedis = null;
        Long amount = 0L;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            amount = wjedis.zrem(key, member);
        } catch (Exception e) {
            log.error("zrem from jedis error. key:{} , member:{}", key, member);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
        return amount;
    }

    public Set<Map<String, Object>> zrevrange(String key, Long begin, Long end) {
        Jedis rjedis = null;
        Set<Map<String, Object>> set = Sets.newLinkedHashSet();
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            Set<Tuple> tuples = rjedis.zrevrangeWithScores(key, begin, end);
            for (Tuple tuple : tuples) {
                Map<String, Object> map = Maps.newHashMap();
                map.put("member", tuple.getElement());
                map.put("score", tuple.getScore());
                set.add(map);
            }
        } catch (Exception e) {
            log.error("zrevrange from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return set;
    }

    public Set<Tuple> zrevrangeWithScores(String key, long begin, long end) {
        Jedis rjedis = null;
        Set<Tuple> tuples = Sets.newHashSet();
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            tuples = rjedis.zrevrangeWithScores(key, begin, end);
        } catch (Exception e) {
            log.error("zrevrangeWithScores from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return tuples;
    }


    public Long zcount(String key, double begin, double end) {
        Jedis rjedis = null;
        Long count = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            count = rjedis.zcount(key, begin, end);
        } catch (Exception e) {
            log.error("zcount from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return count;
    }


    /**
     * 获取sorted set指定区间数据，按score从低到高
     *
     * @param key
     * @param begin
     * @param end
     * @return
     */
    public Set<Map<String, Object>> zrange(String key, Integer begin, Integer end) {
        Jedis rjedis = null;
        Set<Map<String, Object>> set = Sets.newLinkedHashSet();
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            Set<Tuple> tuples = rjedis.zrangeWithScores(key, begin, end);
            for (Tuple tuple : tuples) {
                Map<String, Object> map = Maps.newHashMap();
                map.put("member", tuple.getElement());
                map.put("score", tuple.getScore());
                set.add(map);
            }
        } catch (Exception e) {
            log.error("zrange from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return set;
    }

    public Set<Tuple> zrangeWithScores(String key, long begin, long end) {
        Jedis rjedis = null;
        Set<Tuple> tuples = Sets.newHashSet();
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            tuples = rjedis.zrangeWithScores(key, begin, end);
        } catch (Exception e) {
            log.error("zrange from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return tuples;
    }

    public Set<Tuple> zrangeByScoreWithScores(String key, long begin, long end, int offset, int count) {
        Jedis rjedis = null;
        Set<Tuple> tuples = Sets.newHashSet();
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            tuples = rjedis.zrangeByScoreWithScores(key, begin, end, offset, count);
        } catch (Exception e) {
            log.error("zrange from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return tuples;
    }



    /**
     * 获取sorted set中成员排名，按score从低到高
     *
     * @param key
     * @param member
     * @return
     */
    public Long zrank(String key, String member) {
        Jedis rjedis = null;
        Long ranking = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            ranking = rjedis.zrank(key, member);
        } catch (Exception e) {
            log.error("zrank from redis error. key:{}, member:{}", key, member, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return ranking;
    }

    /**
     * 获取sorted set中成员排名，从高到低
     *
     * @param key
     * @param member
     * @return
     */
    public Long zrevrank(String key, String member) {
        Jedis rjedis = null;
        Long ranking = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            ranking = rjedis.zrevrank(key, member);
        } catch (Exception e) {
            log.error("zrevrank from redis error. key:{}, member:{}", key, member, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return ranking;
    }

    /**
     * 获取sorted set中成员score
     *
     * @param key
     * @param member
     * @return
     */
    public Double zscore(String key, String member) {
        Jedis rjedis = null;
        Double ranking = new Double(0);
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            ranking = rjedis.zscore(key, member);
        } catch (Exception e) {
            log.error("zrevrank from redis error. key:{}, member:{}", key, member, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return ranking;
    }

    /**
     * 获取sorted set中成员score
     *
     * @param key
     * @return
     */
    public Long zcard(String key) {
        Jedis rjedis = null;
        Long size = 0L;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            size = rjedis.zcard(key);
        } catch (Exception e) {
            log.error("zcard from redis error. key:{}, member:{}", key, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }

        return size;
    }

    /**
     * 设置key过期时间
     *
     * @param key
     * @param seconds
     * @return
     */
    public Boolean expire(String key, Integer seconds) {
        Jedis wjedis = null;
        Long size = 0L;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            Long result = wjedis.expire(key, seconds);

            return result == 1 ? true : false;
        } catch (Exception e) {
            log.error("expire from redis error. key:{}, member:{}", key, e);
        } finally {
            if (wjedis != null) {
                this.writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return false;
    }

    /**
     * 设置key过期时间
     *
     * @param key
     * @param seconds 到期时间
     * @return
     */
    public Boolean expireAt(String key, Long seconds) {
        Jedis wjedis = null;
        Long size = 0L;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            Long result = wjedis.expireAt(key, seconds);

            return result == 1 ? true : false;
        } catch (Exception e) {
            log.error("expire from redis error. key:{}, member:{}", key, e);
        } finally {
            if (wjedis != null) {
                this.writeJedisPoolManager.returnJedis(wjedis);
            }
        }

        return false;
    }

    /**
     * 获取sorted set指定区间member数据
     *
     * @param key
     * @param begin
     * @param end
     * @return
     */
    public Set<String> zrangeMembers(String key, Integer begin, Integer end) {
        Jedis rjedis = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            Set<String> sets = rjedis.zrange(key, begin, end);
            return sets;
        } catch (Exception e) {
            log.error("zrange from redis error. key:{}, begin:{}, end:{}", key, begin, end, e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return null;
    }


    /**
     * 添加sorted数据 同时限制大小
     *
     * @param key
     * @param score
     * @param member
     * @param limitSize
     */
    public void zaddLimit(String key, double score, String member, int limitSize) {
        Jedis rjedis = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            Pipeline p = rjedis.pipelined();
            p.zadd(key, score, member);
            p.zremrangeByRank(key, limitSize, -1);
            p.sync();
        } catch (Exception e) {
            log.error("zaddLimit from redis error. key:{},e{}", e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }
    }

    /**
     * 添加sorted数据 同时限制大小
     *
     * @param key
     * @param map
     * @param limitSize
     */
    public void zaddLimit(String key, Map<String, Double> map, int limitSize) {
        Jedis rjedis = null;
        try {
            rjedis = this.readJedisPoolManager.getJedis();
            Pipeline p = rjedis.pipelined();
            p.zadd(key, map);
            p.zremrangeByRank(key, limitSize, -1);
            p.sync();
        } catch (Exception e) {
            log.error("zaddLimit from redis error. key:{},e{}", e);
        } finally {
            if (rjedis != null) {
                this.readJedisPoolManager.returnJedis(rjedis);
            }
        }
    }

    /**
     * zset 添加多条数据
     */
    public void zadd(String key, Map<String, Double> map, boolean clean) {
        Jedis wjedis = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            Pipeline p = wjedis.pipelined();
            if (clean) {
                p.zremrangeByRank(key, 0, -1);
            }
            p.zadd(key, map);
            p.sync();
        } catch (Exception e) {
            log.error("zincrby from jedis error. key:{} score:{} member:{}", key);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
    }


    /**
     * 通过redis的Pipeline 批量添加list数据
     */
    public boolean lpushList(String key, List<?> list) {
        Jedis wjedis = null;
        boolean status = false;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            Pipeline p = wjedis.pipelined();
            if (list != null && !list.isEmpty()) {
                for (Object el : list) {
                    p.lpush(key, String.valueOf(el));
                }
            }
            p.sync();
            status = true;
            return status;
        } catch (Exception e) {
            log.error("lpushList from jedis error. key:{}  list:{}", key, list);
            return status;
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }

        }
    }


    /**
     * 执行脚本
     */
    public Object eval(String script, int keyCount, String... params) {
        Jedis wjedis = null;
        Object result = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            result = wjedis.eval(script, keyCount, params);
        } catch (Exception e) {
            log.error("eval from jedis error  params:{}", params);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }

        }
        return result;
    }

    /**
     * 确定一个给定的值是否存在
     *
     * @param key
     * @param member
     * @return
     */
    public boolean sismember(String key, String member) {
        Jedis rjedis = null;
        try {
            rjedis = readJedisPoolManager.getJedis();
            boolean s = rjedis.sismember(key, member);
            return s;
        } catch (Exception e) {
            log.error("sismember from jedis error. key:{} member:{}", key, member);
        } finally {
            if (rjedis != null) {
                readJedisPoolManager.returnJedis(rjedis);
            }
        }
        return false;
    }

    /**
     * 向Set添加一条记录，如果member已存在返回0,否则返回1
     *
     * @param key
     * @param member
     * @return
     */
    public long sadd(String key, String member) {
        Jedis wjedis = null;
        try {
            wjedis = writeJedisPoolManager.getJedis();
            return wjedis.sadd(key, member);
        } catch (Exception e) {
            log.error("sadd from jedis error. key:{}", key);
        } finally {
            if (wjedis != null) {
                writeJedisPoolManager.returnJedis(wjedis);
            }
        }
        return 0;
    }

    /**
     * 检测key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exits(String key) {
        Jedis wjedis = null;
        try {
            wjedis = this.writeJedisPoolManager.getJedis();
            return wjedis.exists(key);
        } catch (Exception e) {
            log.error("expire from redis error. key:{}, member:{}", key, e);
        } finally {
            if (wjedis != null) {
                this.writeJedisPoolManager.returnJedis(wjedis);
            }
        }
        return false;
    }
}
